﻿using PcapDotNet.Core;
using PcapDotNet.Packets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Pcap.NetSample
{
    class 异步抓取数据包
    {
        #region 异步抓取数据包
        /// <summary>
        /// https://github.com/PcapDotNet/Pcap.Net/wiki/Pcap.Net-Tutorial-Opening-an-adapter-and-capturing-the-packets
        /// 打开网络适配器抓取数据包
        /// </summary>
        internal static void OpeningAnAdapterAndCapturingThePackets()
        {
            // Retrieve the device list from the local machine
            IList<LivePacketDevice> allDevices = LivePacketDevice.AllLocalMachine;

            if (allDevices.Count == 0)
            {
                Console.WriteLine("No interfaces found! Make sure WinPcap is installed.");
                return;
            }

            // Print the list
            for (int i = 0; i != allDevices.Count; ++i)
            {
                LivePacketDevice device = allDevices[i];
                Console.Write((i + 1) + ". " + device.Name);
                if (device.Description != null)
                    Console.WriteLine(" (" + device.Description + ")");
                else
                    Console.WriteLine(" (No description available)");
            }

            int deviceIndex = 0;
            do
            {
                Console.WriteLine("Enter the interface number (1-" + allDevices.Count + "):");
                string deviceIndexString = Console.ReadLine();
                if (!int.TryParse(deviceIndexString, out deviceIndex) ||
                    deviceIndex < 1 || deviceIndex > allDevices.Count)
                {
                    deviceIndex = 0;
                }
            } while (deviceIndex == 0);

            // Take the selected adapter
            PacketDevice selectedDevice = allDevices[deviceIndex - 1];

            // Open the device
            using (PacketCommunicator communicator =
                selectedDevice.Open(65536,                                  // portion of the packet to capture
                                                                            // 65536 guarantees that the whole packet will be captured on all the link layers
                                    PacketDeviceOpenAttributes.Promiscuous, // promiscuous mode
                                    1000))                                  // read timeout
            {
                Console.WriteLine("Listening on " + selectedDevice.Description + "...");

                //string ipV4Str = selectedDevice.Addresses.FirstOrDefault(x => x.Address.Family == SocketAddressFamily.Internet)?.Address

                //string filterRule = "(ip and tcp) and (host 172.105.71.82 or host 192.168.199.1)"; // 过滤协议和ip
                //string filterRule = "ether host 1C-87-2C-58-21-CB"; // 过滤mac地址
                string filterRule = "ether dst 1C-87-2C-58-21-CB"; // 过滤目标mac地址
                using (BerkeleyPacketFilter filter = communicator.CreateFilter(filterRule))
                {
                    // Set the filter
                    communicator.SetFilter(filter);
                }

                // start the capture
                communicator.ReceivePackets(0, PacketHandler);
            }
        }

        // Callback function invoked by Pcap.Net for every incoming packet
        private static void PacketHandler(Packet packet)
        {
            Console.WriteLine($"{packet.Timestamp.ToString("yyyy-MM-dd hh:mm:ss.fff")} length: {packet.Length}");
            Console.WriteLine($"\tEthernet: Source [{packet.Ethernet.Source}];Destination: [{packet.Ethernet.Destination}];Type[{packet.Ethernet.EtherType}]");
            Console.WriteLine($"\tIP: Source [{packet.Ethernet.IpV4.Source}];Destination: [{packet.Ethernet.IpV4.Destination}];Current Destination[{packet.Ethernet.IpV4.CurrentDestination}];Protocol:[{packet.Ethernet.IpV4.Protocol}]");
        }
        #endregion
    }
}
